﻿using System;
using System.Configuration;
using System.Data;
using System.Reflection;
using System.Web.Configuration;
using System.Web.Handlers;
using System.Web.UI;
using System.Xml.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace Trentacular.SharePoint.ASPNet35Upgrade
{
    /// <summary>
    /// Feature receiver that adds ASP.Net 3.5 entries to the web config
    /// </summary>
    public class ASPNet35UpgradeFeatureReceiver : BaseFeatureReceiver<SPWebApplication>
    {
        private readonly Assembly SystemWebExtensionsAssembly = typeof(ScriptManager).Assembly;
        private readonly Assembly SystemCoreAssembly = typeof(Action).Assembly;
        private readonly Assembly SystemXmlLinqAssembly = typeof(XObject).Assembly;
        private readonly Assembly SystemDataDataSetExtensionsAssembly = typeof(DataRowComparer).Assembly;

        public override void FeatureActivated(SPWebApplication webApp, SPFeatureReceiverProperties properties)
        {
            var webConfig = new SPWebConfigModificationHelper(webApp, properties);
            AddModifications(webConfig);
            webConfig.SaveChanges();
        }

        public override void FeatureDeactivating(SPWebApplication webApp, SPFeatureReceiverProperties properties)
        {
            var webConfig = new SPWebConfigModificationHelper(webApp, properties);
            webConfig.RemoveAllOwnedModifications();
            webConfig.SaveChanges();
        }

        private void AddModifications(SPWebConfigModificationHelper webConfig)
        {
            var type = SPWebConfigModificationType.Add;

            AddSectionGroupModifications(webConfig, type);

            //<SafeControl Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            //    Namespace="System.Web.UI" TypeName="*" Safe="True" />
            webConfig.ModifySafeControl(SystemWebExtensionsAssembly, "System.Web.UI", "*", true, type);

            AddHttpHandlerModifications(webConfig, type);

            //<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            webConfig.ModifyHttpModule<ScriptModule>("ScriptModule", WebConfigEntryActionType.Add, type);

            AddAssemblyModifications(webConfig, type);

            AddControls(webConfig, type);

            AddDependentAssemblies(webConfig, type);

            AddRootLevelModifications(webConfig, type);
        }

        private void AddDependentAssemblies(SPWebConfigModificationHelper webConfig, SPWebConfigModificationType type)
        {
            //<dependentAssembly>
            //  <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35" />
            //  <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" />
            //</dependentAssembly>
            webConfig.ModifyDependentAssembly("System.Web.Extensions", "31bf3856ad364e35", "1.0.0.0-1.1.0.0", "3.5.0.0", type);

            //<dependentAssembly>
            //  <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35" />
            //  <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0" />
            //</dependentAssembly>
            webConfig.ModifyDependentAssembly("System.Web.Extensions.Design", "31bf3856ad364e35", "1.0.0.0-1.1.0.0", "3.5.0.0", type);
        }

        private void AddSectionGroupModifications(SPWebConfigModificationHelper webConfig, SPWebConfigModificationType type)
        {
            //   <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
            //     <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
            //       <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
            //       <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
            //         <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" />
            //         <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
            //         <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
            //         <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />
            //       </sectionGroup>
            //     </sectionGroup>
            //   </sectionGroup>
            var sysWebExtGroup = new SectionGroup<SystemWebExtensionsSectionGroup>
            {
                Name = "system.web.extensions"
            };

            webConfig.ModifySectionGroup(sysWebExtGroup, type);

            // If removing, exit since we just obliterated the entire section
            if (type == SPWebConfigModificationType.Remove)
                return;

            webConfig.SaveChanges();

            var scriptingGroup = new SectionGroup<ScriptingSectionGroup>
            {
                Name = "scripting",
                Parent = sysWebExtGroup
            };
            webConfig.ModifySectionGroup(scriptingGroup, type);
            webConfig.SaveChanges();

            var scriptResourceHandlerSection = new Section<ScriptingScriptResourceHandlerSection>
            {
                Name = "scriptResourceHandler",
                Parent = scriptingGroup,
                RequirePermission = false,
                AllowDefinition = ConfigurationAllowDefinition.MachineToApplication
            };
            webConfig.ModifySection(scriptResourceHandlerSection, type);

            var webServicesGroup = new SectionGroup<ScriptingWebServicesSectionGroup>
            {
                Name = "webServices",
                Parent = scriptingGroup
            };
            webConfig.ModifySectionGroup(webServicesGroup, type);
            webConfig.SaveChanges();

            var jsonSerializationSection = new Section<ScriptingJsonSerializationSection>
            {
                Name = "jsonSerialization",
                Parent = webServicesGroup,
                RequirePermission = false,
                AllowDefinition = ConfigurationAllowDefinition.MachineToApplication
            };
            webConfig.ModifySection(jsonSerializationSection, type);

            var profileServiceSection = new Section<ScriptingProfileServiceSection>
            {
                Name = "profileService",
                Parent = webServicesGroup,
                RequirePermission = false,
                AllowDefinition = ConfigurationAllowDefinition.MachineToApplication
            };
            webConfig.ModifySection(profileServiceSection, type);

            var authenticationServiceSection = new Section<ScriptingAuthenticationServiceSection>
            {
                Name = "authenticationService",
                Parent = webServicesGroup,
                RequirePermission = false,
                AllowDefinition = ConfigurationAllowDefinition.MachineToApplication
            };
            webConfig.ModifySection(authenticationServiceSection, type);

            var roleServiceSection = new Section<ScriptingRoleServiceSection>
            {
                Name = "roleService",
                Parent = webServicesGroup,
                RequirePermission = false,
                AllowDefinition = ConfigurationAllowDefinition.MachineToApplication
            };
            webConfig.ModifySection(roleServiceSection, type);
        }

        private void AddHttpHandlerModifications(SPWebConfigModificationHelper webConfig, SPWebConfigModificationType type)
        {
            //    <remove verb="*" path="*.asmx" />
            var removeHandler = new HttpHandlerAction("*.asmx", null, "*");
            webConfig.ModifyHttpHandler(removeHandler, WebConfigEntryActionType.Remove, type);

            //    <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            var scriptHandlerFactory = new HttpHandlerAction("*.asmx", "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35", "*");
            webConfig.ModifyHttpHandler(scriptHandlerFactory, WebConfigEntryActionType.Add, type);

            //    <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            scriptHandlerFactory.Path = "*_AppService.axd";
            webConfig.ModifyHttpHandler(scriptHandlerFactory, WebConfigEntryActionType.Add, type);

            //    <add verb="GET,HEAD" path="ScriptResource.axd" validate="false" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            var scriptResourceHandler = new HttpHandlerAction("ScriptResource.axd", typeof(ScriptResourceHandler).AssemblyQualifiedName, "GET,HEAD");
            webConfig.ModifyHttpHandler(scriptResourceHandler, WebConfigEntryActionType.Add, type);
        }

        private void AddAssemblyModifications(SPWebConfigModificationHelper webConfig, SPWebConfigModificationType type)
        {
            //<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
            webConfig.ModifyCompilationAssembly(SystemCoreAssembly, type);

            //<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            webConfig.ModifyCompilationAssembly(SystemWebExtensionsAssembly, type);

            //<add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
            webConfig.ModifyCompilationAssembly(SystemXmlLinqAssembly, type);

            //<add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
            webConfig.ModifyCompilationAssembly(SystemDataDataSetExtensionsAssembly, type);
        }

        private void AddControls(SPWebConfigModificationHelper webConfig, SPWebConfigModificationType type)
        {
            //<controls>
            //    <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            //    <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            //</controls>
            webConfig.EnsureControlsSection();
            webConfig.ModifyControl("asp", "System.Web.UI", SystemWebExtensionsAssembly, type);
            webConfig.ModifyControl("asp", "System.Web.UI.WebControls", SystemWebExtensionsAssembly, type);
        }

        private void AddRootLevelModifications(SPWebConfigModificationHelper webConfig, SPWebConfigModificationType type)
        {
            webConfig.ModifyRootSection("system.codedom",
@"<system.codedom>
    <compilers>
      <compiler language=""c#;cs;csharp"" extension="".cs"" type=""Microsoft.CSharp.CSharpCodeProvider,System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"" warningLevel=""4"">
        <providerOption name=""CompilerVersion"" value=""v3.5"" />
        <providerOption name=""WarnAsError"" value=""false"" />
      </compiler>
    </compilers>
  </system.codedom>", type);

            webConfig.ModifyRootSection("system.webServer",
@"<system.webServer>
    <validation validateIntegratedModeConfiguration=""false"" />
    <modules>
      <remove name=""ScriptModule"" />
      <add name=""ScriptModule"" preCondition=""managedHandler"" type=""System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"" />
    </modules>
    <handlers>
      <remove name=""WebServiceHandlerFactory-Integrated"" />
      <remove name=""ScriptHandlerFactory"" />
      <remove name=""ScriptHandlerFactoryAppServices"" />
      <remove name=""ScriptResource"" />
      <add name=""ScriptHandlerFactory"" verb=""*"" path=""*.asmx"" preCondition=""integratedMode"" type=""System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"" />
      <add name=""ScriptHandlerFactoryAppServices"" verb=""*"" path=""*_AppService.axd"" preCondition=""integratedMode"" type=""System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"" />
      <add name=""ScriptResource"" verb=""GET,HEAD"" path=""ScriptResource.axd"" preCondition=""integratedMode"" type=""System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"" />
    </handlers>
  </system.webServer>", type);
        }
    }
}
